/*
 * This file is part of the Try! Engine project.
 *
 * Copyright 2010-2011 Emanuele Bertoldi. All rights reserved.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * You should have received a copy of the modified BSD License along with this
 * program. If not, see <http://www.opensource.org/licenses/bsd-license.php>
 */

#include "animable.h"
#include "graphicsmanager.h"

using namespace Try;

PropertyName Animable::name  = "try.graphics.animable";

Animable::Animable(Object* owner, Model3DNode* node)
    : Property(Animable::name, owner),
      m_node(node)
{
    graphics->addListener(this);
}

Animable::~Animable()
{
    graphics->removeListener(this);

    this->stopAllAnimations();
}

int Animable::addAnimation(const String& filename, float weight, int layer)
{
    if (m_node)
        return m_node->addAnimation(filename, weight, layer);

    return -1;
}

void Animable::removeAllAnimations()
{
    if (m_node)
        m_node->removeAllAnimations();
}

void Animable::removeAnimation(int animation_id)
{
    if (m_node)
        m_node->removeAnimation(animation_id);
}

void Animable::runAllAnimations(float weight, float speed)
{
    if (m_node)
    {
        for (int i=0; i<m_node->animationCount(); i++)
            this->runAnimation(i, weight, speed);
    }
}

void Animable::runAnimation(int animation_id, float weight, float speed)
{
    if (m_node)
    {
        m_node->changeAnimationWeight(animation_id, weight);
        m_runningAnimations[animation_id] = speed;
    }
}

void Animable::pauseAllAnimations()
{
    if (m_node)
    {
        for (int i=m_node->animationCount(); i>0; i--)
            this->pauseAnimation(i-1);
    }
}

void Animable::pauseAnimation(int animation_id)
{
    if (m_node)
    {
        m_runningAnimations.erase(animation_id);
        m_node->changeAnimationWeight(animation_id, 0);
    }
}

void Animable::stopAllAnimations()
{
    if (m_node)
    {
        for (int i=m_node->animationCount(); i>0; i--)
            this->stopAnimation(i-1);
    }
}

void Animable::stopAnimation(int animation_id)
{
    if (m_node)
    {
        this->pauseAnimation(animation_id);

        m_node->resetAnimation(animation_id);
    }
}

void Animable::changeAnimationWeight(int animation_id, float weight)
{
    if (m_node)
        m_node->changeAnimationWeight(animation_id, weight);
}

int Animable::animationCount() const
{
    if (m_node)
        return m_node->animationCount();

    return 0;
}

bool Animable::isAnimationRunning(int animation_id) const
{
    if (m_runningAnimations.find(animation_id) == m_runningAnimations.end())
        return false;

    return true;
}

float Animable::animationTime(int animation_id) const
{
    if (m_node)
        return m_node->animationTime(animation_id);

    return 0;
}

float Animable::animationWeight(int animation_id) const
{
    if (m_node)
        return m_node->animationWeight(animation_id);

    return 0;
}

Property* Animable::copy(Object* owner) const
{
    return 0;
}

void Animable::onRenderStarted(double dt)
{
    if (m_node)
    {
        std::map<int, float>::iterator it = m_runningAnimations.begin();

        while (it != m_runningAnimations.end())
        {
            m_node->updateAnimation((*it).first, dt * (*it).second);
            it++;
        }
    }
}
